# -*- coding: utf-8 -*-
"""
Created on Thu Oct 17 08:53:41 2019

@author: shosborn
"""

from gurobipy import *
from random import random, gauss, uniform, choice
import pandas as pd

#index values for returned tuples
TASK1=0
TASK2=1
PERIOD=2
UTIL=3

class RTCSA_ILP:
    #create variables for frame sizes
    
    def __init__(self, taskSystem):
        self.solver=Model()
        self.taskSystem=taskSystem
        
   
    
    def setSolverParams(self):
        taskSystem=self.taskSystem
        self.solver.setParam("TimeLimit", taskSystem.timeout)
        self.solver.setParam("SolutionLimit", taskSystem.solutionLimit)
        self.solver.setParam(GRB.Param.Threads, taskSystem.threadsPerTest)
        self.threadedUtil=self.solver.addVar(vtype=GRB.CONTINUOUS)
        self.solver.setObjective(self.threadedUtil, GRB.MINIMIZE)

    
    def makePairs(self):
        self.setSolverParams()
        self.createSchedVars()
        self.allJobsScheduled()
        self.solver.optimize()
        
        #Return a list showing all pairs
        #Note some items are paired with themselves
        thePairs=[]
        for k in range(len(self.schedVarsP.index)):
            if self.schedVarsP['schedVar'].iloc[k].x==1:
                i=self.schedVarsP['taskID_1'].iloc[k]
                j=self.schedVarsP['taskID_2'].iloc[k]
                max_cost = max(self.taskSystem.allTasks[i].allCosts[j], self.taskSystem.allTasks[j].allCosts[i])
                thisPair=(i, 
                          j,
                          self.taskSystem.allTasks[i].period,
                          max_cost / self.taskSystem.allTasks[i].period)
                thePairs.append(thisPair)
        return (thePairs, self.solver.runtime)
    
        #return self.solver.getAttr(GRB.Attr.Status)
        
        
        '''
        print("task1, task2")
        for k in range(len(self.schedVarsP.index)):
            if self.schedVarsP['schedVar'].iloc[k].x==1:
                print(self.schedVarsP['taskID_1'].iloc[k], self.schedVarsP['taskID_2'].iloc[k])

        '''
        


    def createSchedVars(self):
        taskSystem=self.taskSystem
        self.schedVars={'taskID_1'      : [],
                        'taskID_2'      : [],
                        'schedVar'   : []
                }

        expr=LinExpr()
        for i in range(taskSystem.nTotal):
            for j in range(i, taskSystem.nTotal):
                
                periodsMatch=(taskSystem.allTasks[i].period==taskSystem.allTasks[j].period)
                #pairedCost=taskSystem.allTasks[i].allCosts[j]
                pairedCost = max(self.taskSystem.allTasks[i].allCosts[j], self.taskSystem.allTasks[j].allCosts[i])
                
                if periodsMatch and pairedCost<=taskSystem.allTasks[i].period:
                
                    pairedUtil=pairedCost/taskSystem.allTasks[i].period
                    var=self.solver.addVar(lb=0, ub=1, vtype=GRB.BINARY)
                    self.schedVars['taskID_1'].append(i)
                    self.schedVars['taskID_2'].append(j)
                    self.schedVars['schedVar'].append(var)

                    expr += var * pairedUtil
        self.schedVarsP=pd.DataFrame(self.schedVars)
        #define total threaded utilization
        self.solver.addConstr(lhs=self.threadedUtil, rhs=expr, sense=GRB.EQUAL)
        
               
    def allJobsScheduled (self):
        taskSystem=self.taskSystem
        for i in range(taskSystem.nTotal):
            schedVarsThisTask=self.schedVarsP[(self.schedVarsP['taskID_1']==i) | (self.schedVarsP['taskID_2']==i) ]
            expr=LinExpr()
            for k in range(len(schedVarsThisTask.index)):
                expr += schedVarsThisTask['schedVar'].iloc[k]
            #for every i, paired with exactly one other (include itself as an option)
            self.solver.addConstr(lhs=expr, rhs=1, sense=GRB.EQUAL)

                
                
            
        

 
